package com.xiangyueEducation.uploaderCloud.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.xiangyueEducation.uploaderCloud.context.BaseContext;
import com.xiangyueEducation.uploaderCloud.pojo.dto.PageQuery;
import com.xiangyueEducation.uploaderCloud.pojo.dto.ChangeStatusDTO;
import com.xiangyueEducation.uploaderCloud.pojo.dto.StudenteFeedbackDTO;
import com.xiangyueEducation.uploaderCloud.pojo.dto.TeacherAdviceDTO;
import com.xiangyueEducation.uploaderCloud.pojo.entity.Diagnose;
import com.xiangyueEducation.uploaderCloud.pojo.entity.User;
import com.xiangyueEducation.uploaderCloud.pojo.vo.PageVo;
import com.xiangyueEducation.uploaderCloud.service.DiagnoseService;
import com.xiangyueEducation.uploaderCloud.service.DoctorService;
import com.xiangyueEducation.uploaderCloud.utils.Result;
import com.xiangyueEducation.uploaderCloud.utils.enums.ResultCodeEnum;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@RestController
@CrossOrigin
@RequestMapping("/appointment")
public class AppointmentController {
    @Resource
    private DiagnoseService diagnoseService;
    @Resource
    private DoctorService doctorService;
    private final Map<Long,SseEmitter> pool = new ConcurrentHashMap<>();

    //整体流程：
    //学生端发送请求，创建诊断表中的数据，状态为未查看，推送给前端教师，有新的消息需要查收
    //教师登录之后去查诊断表，如果诊断表中信息未查看反馈给老师
    //前端登录的时候就要注册sse，建立连接
    //登录，查诊断表，建立sse连接
    // 三个请求，异步执行
    // 学生预约接口
    @PostMapping("/student")
    public Result appointment(@RequestBody Diagnose diagnose){
        log.info("学生预约信息{}",diagnose);
        diagnose.setPatientUserId(BaseContext.getCurrentUser().getId());

        //预约时间在当前时间之前，则报错
        //也就是当前时间在预约事件之后
        if(LocalDateTime.now().isAfter(diagnose.getAppointTime())){
         return Result.build(diagnose.getAppointTime(), ResultCodeEnum.APPOINTMENT_TIME_MUST_AFTER_NOW);
        }
        if(doctorService.selectByUserId(diagnose.getDoctorUserId())==null){
            return Result.build("doctorId:"+diagnose.getDoctorUserId()+" not exist",ResultCodeEnum.DOCTOR_NOT_EXIST);
        }

        diagnoseService.appointment(diagnose);
        //发消息给订阅了此消息的医生
        SseEmitter sseEmitter = pool.get(diagnose.getDoctorUserId());
        //如果没有说明没上线，不通知
        if (sseEmitter==null){
            return Result.ok(ResultCodeEnum.SUCCESS);
        }
        //上线了
        try {
            //向sse通道中发消息给教师
            sseEmitter.send(JSONUtil.toJsonStr(diagnose));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return Result.ok(ResultCodeEnum.SUCCESS);
    }
    // sse连接接口(教师订阅随时给他推消息的通道)
    //访问这个接口会收到信息
    //id为医生id，每个医生上线的时候都有一条通道
    @GetMapping("/teacher/subscribe")
    public SseEmitter subscribe(HttpServletResponse httpServletResponse){
        Long doctorUserId = BaseContext.getCurrentUser().getId();
        log.info("sse连接开启》》》》》》》》》》》》》》》》》》》》》》》》");
        //尝试从连接池中获取
     SseEmitter sseEmitter = pool.get(doctorUserId);
     //获取不到
     if (sseEmitter==null){
         //表示永不超时连接
         sseEmitter = new SseEmitter(Long.MAX_VALUE);
         sseEmitter.onCompletion(()->pool.remove(doctorUserId));
         sseEmitter.onTimeout(()->pool.remove(doctorUserId));
         pool.put(doctorUserId,sseEmitter);
     }
     httpServletResponse.setHeader("Cache-Control", "no-cache");
     httpServletResponse.setHeader("Connection", "keep-alive");
     httpServletResponse.setContentType("text/event-stream");
     return sseEmitter;
    }
    // 教师查询预约表接口，共有两个
    //一个查询未查看的的数量
    @GetMapping("/teacher/countAppointment")
    public Result getCount(){
        //查看本人的
        Long count = diagnoseService.count(BaseContext.getCurrentUser().getId());
        return Result.ok(count);
    }

    // 一个查询分页查询全部的
    @GetMapping("/all")
    public Result getAll(PageQuery pageQuery){
        Result result = pageQuery.checkPage();
        if (result!=null){
            return result;
        }
        //分页查询指定用户id的会诊记录
        PageVo pageVo = diagnoseService.getPages(pageQuery);
        return Result.ok(pageVo);
    }
    //学生做完心理辅导之后
    //学生要对本次会诊做出评价并打分
    @PutMapping("/student/feedback")
    public Result addFeedback(@RequestBody StudenteFeedbackDTO studenteFeedbackDTO ){
        String feedback = studenteFeedbackDTO.getFeedback();
        if (feedback==null||feedback.isBlank()){
            return Result.build(studenteFeedbackDTO,ResultCodeEnum.FeedbackIsBlank);
        }
        Diagnose diagnose = BeanUtil.copyProperties(studenteFeedbackDTO, Diagnose.class);

        //更新会诊记录
         diagnoseService.updateAllById(diagnose);
        // 对这个老师打分
        diagnoseService.mark(studenteFeedbackDTO);
        return Result.ok(ResultCodeEnum.SUCCESS);
    }
    // 老师要给出结果
    @PutMapping("/teacher/advice")
    public Result addAdvice(@RequestBody TeacherAdviceDTO teacherAdviceDTO ){
        String advice = teacherAdviceDTO.getAdvice();
        if (advice==null||advice.isBlank()){
            return Result.build(teacherAdviceDTO,ResultCodeEnum.AdviceIsBlank);
        }
        Diagnose diagnose = BeanUtil.copyProperties(teacherAdviceDTO, Diagnose.class);
        //更新会诊记录
        diagnoseService.updateAllById(diagnose);
        return Result.ok(ResultCodeEnum.SUCCESS);
    }
    //学生批量改变状态，根据学生的id
    //老师批量改变状态，根据教师的用户id
    //改变一批的
    @PutMapping("/all/changeAll")
    public Result cancelAllStudent(@RequestBody ChangeStatusDTO changeStatusDTO ) {
        //由于查询出的是自己的会诊记录，所以此处不对是否修改的是自己的诊断信息进行校验
        System.out.println("我被调用了》》》》》》》》》》》》》》》》》》》。");
        Map<Long, String> idAndStatus = changeStatusDTO.getIdAndStatus();
        for (Map.Entry<Long, String> entry : idAndStatus.entrySet()) {
            Long id = entry.getKey();
            String status = entry.getValue();
            Diagnose diagnose = new Diagnose();
            diagnose.setId(id);
            diagnose.setStatus(status);
            //更新会诊记录
            diagnoseService.updateStatusById(diagnose);
        }

        return Result.ok(ResultCodeEnum.SUCCESS);
    }
}
